/** This class represents a connected member 
 *  @author ChrM */

package info.chrm.jtalkerserver;

import java.net.*;
import java.io.*;
import java.util.*;


public class JTalkerMember {
      // Static Vars
      public static final String USER_TYPE_WEBCLIENT = "webclient";
      public static final String USER_TYPE_PERSISTENT = "persistent";
      public static final String USER_TYPE_CHATROOM = "chatroom";
      // Invalidate after one minute
      // TODO: make session duration variable!
      public static final int SESSION_DURATION = 60000;

      /** Corresponding network thread */
      private JTalkerServerThread myThread = null;
      
      /** Constructor */
      public JTalkerMember (String _userName,
			    String _userIP,
			    String _userPort,
			    String _userStatus,
			    String _userType) {
	 this.userName = _userName;
	 this.userIP = _userIP;
	 this.userPort = _userPort;	 
	 this.userStatus = _userStatus;

	 // TODO: special functions for a chatroom "user"
	 
      
	 if(this.userIP == null)
	    this.userIP = "server";
	 if(this.userPort == null)
	    this.userPort = "-1";
	 if(this.userStatus == null)
	    this.userStatus = "normal";
	 
	 if(_userType == null || 
	       (!_userType.equals(USER_TYPE_WEBCLIENT) && 
		!_userType.equals(USER_TYPE_PERSISTENT) && 
		!_userType.equals(USER_TYPE_CHATROOM)))
	    this.userType = USER_TYPE_PERSISTENT;     // Default
	 else
	    this.userType = _userType;
	 
	 this.userSID = this.generateSessionID();
	 this.userSidGeneratingDate = System.currentTimeMillis();

	 this.isOnline = true;
      }  

      /** Sets the corresponding thread */
      public void setThread(JTalkerServerThread _thread) {
          this.myThread = _thread;
      }

      /** Gets a user info */
      public String getUserInfo() {
	 return (this.userName + " AT " + this.userIP);
      }

      /** Gets a user name */
      public String getUserName() {
	 return this.userName;
      }

      /** Sets users role */
      public boolean setUserRole(String _role) {
	 if(_role.equals(JTalkerParser.GlobalUser.USER) || 
	    _role.equals(JTalkerParser.GlobalUser.ADMIN) ||
	    _role.equals(JTalkerParser.GlobalUser.ROOT)) {
	       this.userRole = _role; 
	       return true;
	 } else
	       return false;	    
      }

      /** Gets users role */
      public String getUserRole() {
	      return this.userRole;
      }

      /** Gets users role as int value */
      public int getUserRoleValue() {
	 if(this.userRole.equals(JTalkerParser.GlobalUser.USER))
		 return 0; 
	 else if(this.userRole.equals(JTalkerParser.GlobalUser.ADMIN))
		 return 1;
	 else if(this.userRole.equals(JTalkerParser.GlobalUser.ROOT))
		 return 2;
	 else
		 return -1;
      }

      /** Gets the Port-Number as int */
      public int getPort() {
	 return Integer.parseInt(this.userPort);
      }

      /** Sets a new IP and Port number. For web-clients only! */
      public boolean updateConnectionData(String _newIP, String _newPort) {
	 if(this.userType.equals(USER_TYPE_WEBCLIENT)) {
	    this.userIP = _newIP;
	    this.userPort = _newPort;
	    return true;
	 }

	 return false;
      }

      /** Gets user status */
      public String getUserStatus() {
	 return this.userStatus;
      }
      
      /** Gets user IP adress */
      public String getUserIP() {
	 return this.userIP;
      }

      /** Gets the Session ID */
      public String getSessionID() {
	 return this.userSID;
      }

      /** Gets user type */
      public String getUserType() {
	 return this.userType;
      }

      /** Checks if this is a chatroom */
      public boolean isChatroom() {
	 return this.userType.equals(JTalkerMember.USER_TYPE_CHATROOM);
      }

      /** Sets user status */
      public void setUserStatus(String _status) {
         if(!this.userStatus.equalsIgnoreCase(_status)) {
	    this.userStatus = _status;
            this.sendUpdateRequestToAll();
         }
      }

      /** Adds a set of messages to the queue */
      public synchronized boolean addMessages(Message [] _messages) {
	 if(this.lockQueue)
	    return false;
	 
	 for( int i = 0; i < _messages.length; i++ ) {
	    this.messageQueue.add(new Message(_messages[i].content, 
					      _messages[i].sender, 
					      _messages[i].type, 
					      _messages[i].subject,
                                              _messages[i].ID));
	 }

         this.sendUpdateRequest();
	 return true;
      }
      
      /** Adds a new message to the queue */
      public synchronized boolean addMessage(String _content, 
                                String _sender, 
				String _type, 
				String _subject,
                                String _id) {
	 if(this.lockQueue)
	    return false;
	 // Extensions for chatroom
	 if(this.userType.equals(JTalkerMember.USER_TYPE_CHATROOM)) {
	    if(!_type.equals("file"))
	       _content = "&lt;b&gt;" + _sender + ":&lt;/b&gt; " + _content;
	    _sender = this.userName;	    
	 }
	 this.messageQueue.add(new Message(_content, _sender, _type, _subject, _id));

         this.sendUpdateRequest();
	 return true;
      }

      /** Gets the number of queued messages */
      public int numOfMsgs() {
	 return this.messageQueue.size();
      }

      /** Gets all messages and delete they after this */
      public synchronized Message [] getMessages () {
	 this.lockQueue = true;
	 Message [] tmpArray = new Message [this.messageQueue.size()];
	 this.messageQueue.toArray(tmpArray);
	 this.messageQueue.clear();
         this.lockQueue = false;
	 return tmpArray;
      }
      
      /** Gets the oldest message and delete this one! */
      public synchronized Message getMessage () {
	 if(!this.messageQueue.isEmpty()) {
	    this.lockQueue = true;
	    Message msg = (Message)this.messageQueue.get(0);
	    this.messageQueue.remove(0);
	    this.lockQueue = false;
	    return msg;
	 } else 
	    return null;
      }

      /** Checks if this Session ID is still valid */
      public boolean isSessionValid() {
	 // Only for webclient
	 if(!this.userType.equals(USER_TYPE_WEBCLIENT))
	    return true;

	 if(this.sessionClosed || (System.currentTimeMillis() - this.userSidGeneratingDate) > JTalkerMember.SESSION_DURATION /* && !this.isOnline*/)
	    return false;
	 else 
	    return true;
      }

      /** Updates the session ID on access */
      public void updateSessionID() {
	 if(!this.sessionClosed)
	    this.userSidGeneratingDate = System.currentTimeMillis();
      }

      /** Makes this session invalid */
      public boolean closeSession() {
	 if(this.userType.equals(USER_TYPE_PERSISTENT))
	    return false;

	 this.sessionClosed = true;
	 return true;
      }

      /** Generates a unique session ID */
      private String generateSessionID() {
	 String in = this.userPort + System.currentTimeMillis();

	 // Use a global hash-method
	 return JTalkerServer.makeHash(in);
      }

      /** Set chatroom Users 
       *  @param _users A list of allowed users for this chatroom (separated by ",") 
       *  @return true, if the user list was created successfull */
      public boolean setChatroomUsers(String _users) {
         if(!this.isChatroom())
             return false;

	 if(_users == null || _users.length() < 1)
	    return false;

	 if(this.chatroomUsers == null)
	    this.chatroomUsers = new ArrayList();
	 else
	    this.chatroomUsers.clear();

	 String [] tmpUsers = _users.split(",");
         String tmpUserName = "";
         
	 for( int i = 0; i < tmpUsers.length; i++ ) {
            tmpUserName = tmpUsers[i].trim();
            if(JTalkerServer.isAllowedUserName(tmpUserName))
	        this.chatroomUsers.add(tmpUserName);
	 }

	 this.makeChatroomUsersListUnique();
	 return true;
      }

      /** Checks if the user list is unique (no multiple user items in the list).
       *  If not, the list will be corrected */
      private synchronized boolean makeChatroomUsersListUnique() {
         if(!this.isChatroom())
             return false;

	 String tmpName = null;
	 int numOfHits = 0;
	 boolean retVal = true;
	 for( int i = 0; i < this.chatroomUsers.size(); i++ ) {
	    tmpName = (String)this.chatroomUsers.get(i);
	    numOfHits = 0;
	    for( int j = 0; j < this.chatroomUsers.size(); j++ ) {
	       if(tmpName.equals((String)this.chatroomUsers.get(j))) {
		  numOfHits++;
		  if(numOfHits > 1) {
		     this.chatroomUsers.remove(j);
		     numOfHits--;
		     j--;
		     retVal = false;
		  }
	       }
	    }
	 }

	 return retVal;
      }

      /** Add charoom user */
      public synchronized boolean addChatroomUser(String _user) {
         if(!this.isChatroom())
             return false;

	 if(_user == null || _user.length() < 1 || !JTalkerServer.isAllowedUserName(_user))
	    return false;
	
	 if(this.chatroomUsers == null)
	    this.chatroomUsers = new ArrayList(); 
	 
	 if(!this.isChatroomUser(_user)) {
	 	this.chatroomUsers.add(_user);
         } else
		 return false;
	 
	 return true;
      }

      /** Removes chatroom user */
      public synchronized boolean removeChatroomUser(String _user) {
         if(!this.isChatroom())
             return false;

	 if(_user == null || _user.length() < 1)
	    return false;
	 
	 if(this.isChatroomUser(_user)) {
		 for( int i = 0; i < this.chatroomUsers.size(); i++ ) {
		    if(_user.equals((String)this.chatroomUsers.get(i))) {
		       this.chatroomUsers.remove(i);
		       return true;
		    }
		 }
	 }

	 return false;	
      }

      /** Sets the chatroom admin */
      public boolean setChatroomAdmin(String _admin) {
         if(!this.isChatroom())
             return false;

	 if(_admin == null || _admin.length() < 1)
	    return false;
	 this.chatroomAdmin = _admin;
	 
	 return this.addChatroomUser(_admin);
      }

      /** Gets chatrooms admin */
      public String getChatroomAdmin() {
         if(!this.isChatroom())
             return "";

	 return this.chatroomAdmin;
      }

      /** Gets all allowed users for this chatroom */
      public String [] getChatroomUsers() {
         if(!this.isChatroom())
             return new String[0];

	 if(this.chatroomUsers == null)
	     return new String[0];

	 String tmpUsers [] = new String [this.chatroomUsers.size()];
	 this.chatroomUsers.toArray(tmpUsers);
	 return tmpUsers;
      }

      /** Checks if a user is member of the chatroom */
      public boolean isChatroomUser(String _user) {
         if(!this.isChatroom())
             return false;

	 String [] tmpList = this.getChatroomUsers();
	 
	 for( int i = 0; i < tmpList.length; i++ ) {
	    if(_user.equals(tmpList[i]))
	       return true;
	 }

	 return false;
      }

      /** Sends the update message to this memeber */
      public boolean sendUpdateRequest() {
         if(this.myThread != null) {
             this.myThread.sendUpdateRequest();
             return true;
         } else
             return false;
      }
      
      /** Sends the update message to all members */
      public boolean sendUpdateRequestToAll() {
         if(this.myThread != null) {
             this.myThread.parent.sendUpdateRequestToAll(this.userName);
             return true;
         } else
             return false;
      }

      // private members
      private String userName = "unnamed";
      private String userIP = "127.0.0.1";
      private String userPort = "1975";
      private String userStatus = null;  // or "normal" or "busy"
      private String userType = JTalkerMember.USER_TYPE_PERSISTENT;
      private String userSID = null;

      // TODO: use roles and contact lists
      private String userRole = JTalkerParser.GlobalUser.USER;
      private String userContactList = JTalkerParser.GlobalUser.CONTACTS_ALL;
      
      private long userSidGeneratingDate = -1;
      private ArrayList messageQueue = new ArrayList();
      private boolean lockQueue = false;
      public boolean isOnline = false;
      public boolean sessionClosed = false;
      // Specials for chatroom
      private ArrayList chatroomUsers = null;	// Allowed users for this chatroom
      private String chatroomAdmin = null;	// Creator of this Chatroom

      /** This inner class reprensents a message */
      public class Message {
	 public Message(String _content, 
	                String _sender, 
			String _type, 
			String _subject,
                        String _ID) {
	    // TODO: add send time!
	    // this.sendtime = _sendtime;
	    this.content = _content;
	    this.sender = _sender;
	    this.type = _type;
	    if(_type == null)
	       this.type = "normal";
	    this.subject = _subject;
            this.ID = _ID;
	 }
	 
	 public String content = null;
	 public String sender = null;
	 public String type = null;
	 public String subject = null;
	 public String ID = null;
      }
}
